﻿
using System;
using System.Xml.Serialization;
using System.IO;
using System.ComponentModel;
using System.Windows;
using System.Diagnostics;
namespace Redbrick.Silverlight.Common
{
	public static partial class Misc
	{
		#region Math

		public static bool IsOdd(this int n)
		{
			return n % 2 == 1;
		}
		public static bool IsEven(this int n)
		{
			return !n.IsOdd();
		}
		/// <summary>
		/// how many didgets in the int?
		/// </summary>
		public static int Length(this int n)
		{
			return n.ToString().Length;
		}
		/// <summary>
		/// is n between (inclusive) lo and hi?
		/// </summary>
		public static bool InclusiveBetween(this int n, int lo, int hi)
		{
			if (n == lo && n == hi) return true;
			if (lo > hi) return (n >= hi && n <= lo);
			return (n >= lo && n <= hi);
		}
		/// <summary>
		/// is n between (inclusive) lo and hi?
		/// </summary>
		public static bool InclusiveBetween(this double n, double lo, double hi)
		{
			if (double.IsNaN(n) || double.IsNaN(lo) || double.IsNaN(hi)) return false;
			if (double.IsInfinity(n) || double.IsInfinity(lo) || double.IsInfinity(hi)) return false;
			if (n == lo && n == hi) return true;
			if (lo > hi) return (n >= hi && n <= lo);
			return (n >= lo && n <= hi);
		}
		/// <summary>
		/// is n between (exclusive) lo and hi?
		/// </summary>
		public static bool ExclusiveBetween(this int n, int lo, int hi)
		{
			if (n == lo && n == hi) return false;
			if (lo > hi) return (n > hi && n < lo);
			return (n > lo && n < hi);
		}
		/// <summary>
		/// is n between (exclusive) lo and hi?
		/// </summary>
		public static bool ExclusiveBetween(this double n, double lo, double hi)
		{
			if (double.IsNaN(n) || double.IsNaN(lo) || double.IsNaN(hi)) return false;
			if (double.IsInfinity(n) || double.IsInfinity(lo) || double.IsInfinity(hi)) return false;
			if (n == lo && n == hi) return false;
			if (lo > hi) return (n > hi && n < lo);
			return (n > lo && n < hi);
		}

		#endregion

		#region Hashing

		/// <summary>
		/// compute the MD5 hash of a byte array
		/// </summary>
		public static string MD5Hash(this byte[] byteArray)
		{
			MD5Managed md5 = new MD5Managed();
			byte[] retVal = md5.ComputeHash(byteArray);
			return retVal.ToHexString();
		}

		/// <summary>
		/// compute the MD5 hash of a string
		/// </summary>
		/// <param name="me"></param>
		/// <returns></returns>
		public static string MD5Hash(this string str)
		{
			MD5Managed md5 = new MD5Managed();

			byte[] retVal = md5.ComputeHash(str.ToByteArray());
			return retVal.ToHexString();
		}

		#endregion

		///get available image codecs
		//public static ImageCodecInfo GetEncoderInfo(String mimeType)
		//{
		//   int j;
		//   ImageCodecInfo[] encoders;
		//   encoders = ImageCodecInfo.GetImageEncoders();
		//   for (j = 0; j < encoders.Length; ++j)
		//   {
		//      if (encoders[j].MimeType.ToUpper() == mimeType.ToUpper())
		//         return encoders[j];
		//   }
		//   return null;
		//}
		public static string DebugMethodInfo(this object me, params object[] itms)
		{
			if (!Debugger.IsAttached) return string.Empty;
			StackTrace trace = new StackTrace();
			var mthd = trace.GetFrame(1).GetMethod();

			string name = mthd.DeclaringType.Name + ".";


			if (mthd.IsConstructor)
			{
				name += mthd.DeclaringType.Name;
			}
			else
			{
				name += mthd.Name;

			}


			var pars = mthd.GetParameters();
			int ndx = 0;
			name += "(";
			foreach (var parInfo in pars)
			{
				string value = "<null>";
				string typename = "";

				if (itms[ndx] != null)
				{
					value = itms[ndx].ToString();
					typename = itms[ndx].GetType().Name;
					typename = typename.Replace(itms[ndx].GetType().Namespace, string.Empty);
				}

				if (ndx > pars.Length) name += ",";

				name += typename + ":"
					  + parInfo.Name + " == "
					  + value;
				ndx++;
			}

			name += ")";
			Debug.WriteLine(name);
			return name;
		}

		public static bool IsVowel(this char ch)
		{
			return ch == 'e' || ch == 'a' || ch == 'o' || ch == 'i' || ch == 'u';
		}
		/// <summary>
		/// remove trailing 0 from the byte array
		/// </summary>
		public static byte[] TrimEnd(this byte[] bites)
		{
			int len = bites.Length;
			while (len > 0 && bites[len - 1] == 0)
			{
				len--;
			}

			if (len > 0 && len != bites.Length)
			{
				byte[] cropped = new byte[len];
				Array.Copy(bites, cropped, len);
				return cropped;
			}
			return bites;
		}

		/// <summary>
		/// classic swap method
		/// </summary>
		public static void Swap<TType>(ref TType lft, ref TType rgt)
		{
			TType temp = lft;
			lft = rgt;
			rgt = temp;
		}


		public static string ToXml<_type>(this _type itm)
		{
			XmlSerializer ser = new XmlSerializer(itm.GetType());
			StringWriter sw = new StringWriter();
			ser.Serialize(sw, itm);
			return sw.ToString();
		}

		public static bool IsDesignTime(this UIElement el)
		{
			if (el == null) return false;
			return DesignerProperties.GetIsInDesignMode(el);
		}

		public static Point TopLeft(this Rect r)
		{
			return new Point(r.Left, r.Top);
		}

		public static Point BottomRight(this Rect r)
		{
			return new Point(r.Right, r.Bottom);
		}

		public static bool Contains(this Rect r, Rect query)
		{
			return r.Contains(query.TopLeft()) &&
					  r.Contains(query.BottomRight());
		}
		public static bool IntersectsWith(this Rect r, Rect query)
		{
			return query.Left.InclusiveBetween(r.Left, r.Right) || // left side
					 query.Right.InclusiveBetween(r.Left, r.Right) || // right side
					 query.Top.InclusiveBetween(r.Top, r.Bottom) || // top
					 query.Bottom.InclusiveBetween(r.Top, r.Bottom); // bottom

		}

	}
}
